package com.avalon.core.db;

import com.avalon.core.context.Context;
import com.avalon.core.exception.AvalonException;
import com.avalon.core.exception.SQLFormatException;
import com.avalon.core.field.Field;
import com.avalon.core.field.Fields;
import com.avalon.core.field.IFieldFormat;
import com.avalon.core.model.Record;
import com.avalon.core.model.RecordRow;
import com.avalon.core.select.builder.SelectBuilder;
import com.avalon.core.select.SelectionField;
import com.avalon.core.util.FieldUtils;
import com.avalon.core.util.FieldValue;
import com.avalon.core.util.ObjectUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
 * 将单表改为Map记录
 * 比如
 * {
 * name: '张三',
 * detail: {
 * age: 18,
 * address: '北京'
 * }
 * }
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class ObjectDataReaderRowHandler extends DataReaderRowHandler {
    public ObjectDataReaderRowHandler(SelectBuilder selectBuilder) {
        super(selectBuilder);
    }

    @Override
    protected void processRow(ResultSet rs, int rowNum) throws SQLException {
        if (ObjectUtils.isNull(record)) {
            record = new Record();
        }
        RecordRow recordRow = new RecordRow();
        for (String sqlName : getColumnNames()) {
            String fieldName;
            String tableName = FieldUtils.getJoinFirstTableString(sqlName);
            fieldName = Fields.camelName(FieldUtils.getJoinFieldString(sqlName));

            SelectionField selectionField;
            String originField = tableName + FieldUtils.getJoinDivision() + fieldName;
            if (selectionFields.containsKey(originField)) {
                selectionField = selectionFields.get(originField);
            } else {
                selectionField = selectBuilder.getField(originField);
                selectionFields.put(originField, selectionField);
            }

            fieldName = selectionField.getOriginField();
            Field field = selectionField.getField();
            Object sqlValue = rs.getObject(sqlName);
            if (ObjectUtils.isNull(sqlValue)) {
                put(recordRow, fieldName, null);
                continue;
            }
            if (field instanceof IFieldFormat) {
                IFieldFormat fieldFormat = (IFieldFormat) field;
                try {
                    FieldValue fieldValue = new FieldValue(fieldFormat.parse(sqlValue));
                    fieldValue.setField(fieldFormat);
                    put(recordRow, fieldName, fieldValue);
                } catch (AvalonException e) {
                    String msg = "字段=" + field.getName() + ",类型=" + field.getClass().getTypeName()
                            + ",格式=" + fieldFormat.getFormat() + ",值=" + sqlValue;
                    Context.getLogger(this).error(msg);
                    throw new SQLFormatException(msg);
                }
            } else {
                put(recordRow, fieldName, sqlValue);
            }
        }

        record.add(recordRow);
    }


    private void put(RecordRow row, String fieldName, Object value) {
        if (ObjectUtils.isNull(value)) {
            if (!FieldUtils.hasJoinSelect(fieldName)) {
                row.put(fieldName, null);
            } else {
                String joinTableString = FieldUtils.getJoinTableString(fieldName);
                String joinFieldString = FieldUtils.getJoinFieldString(fieldName);
                RecordRow lastRecordRow = getLastRecordRow(row, joinTableString);
                lastRecordRow.put(joinFieldString, null);
            }
            return;
        }
        if (!FieldUtils.hasJoinSelect(fieldName)) {
            if (value instanceof FieldValue) {
                row.put(fieldName, (FieldValue)value);
            } else {
                row.put(fieldName, value);
            }
        } else {
            String joinTableString = FieldUtils.getJoinTableString(fieldName);
            String joinFieldString = FieldUtils.getJoinFieldString(fieldName);
            RecordRow lastRecordRow = getLastRecordRow(row, joinTableString);
            if (value instanceof FieldValue) {
                lastRecordRow.put(joinFieldString, (FieldValue)value);
            } else {
                lastRecordRow.put(joinFieldString, value);
            }
        }
    }

    /**
     * 获取最后一个RecordRow，用来保存Json
     *
     * @param row       第一个RecordRow
     * @param tableName 表民 使用.分割
     * @return
     */
    private RecordRow getLastRecordRow(RecordRow row, String tableName) {
        List<String> tables = FieldUtils.getJoinStringList(tableName);

        RecordRow lastRow = row;
        for (String table : tables) {
            if (lastRow.containsKey(table) && lastRow.isRecordRow(table)) {
                lastRow = lastRow.getRecordRow(table);
            } else {
                lastRow = new RecordRow();
                row.put(table, lastRow);
            }
        }
        return lastRow;
    }
}
